/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hhf.flex.ascreator;

import hhf.flex.ascreator.exceptions.IgnoredClassException;
import hhf.flex.ascreator.exceptions.IllegalClassException;
import hhf.flex.ascreator.exceptions.NoAnnotationClassException;
import hhf.flex.ascreator.exceptions.NoCommentClassException;
import hhf.flex.ascreator.exceptions.NoSuperClassException;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * cette classe crée des entité correspondant au methode des service
 * @author HHFrancois
 */
public class ASMethodClassCreator extends ASCreator {

	protected Method method;
	// type du retour de la methode
	protected String returnASType = "void";
	protected boolean basic = false;
	protected boolean temporal = false;
	protected String collectionOf = null;

	public ASMethodClassCreator(String path, Method method, Map<String, Object> options) {
		super(path, options);
		this.method = method;
		// Recupere les types concernés
		Class returnType = method.getReturnType();
		returnASType = ASCreatorTools.getASClassName(returnType, legacyCollection);
		if (returnASType == null) {
			returnASType = returnType.getSimpleName();
		} else {
			basic = true;
			if(returnType.equals(Date.class)) temporal = true;
		}
		if(Collection.class.isAssignableFrom(returnType) || Map.class.isAssignableFrom(returnType)) { // si c'est une collection ou une Map, determine de quoi est une collection
			Type genType = method.getGenericReturnType();
			collectionOf = getASArrayElementType(genType);
		}
	}

	@Override
	protected String getASPackage() {
		Class _clazz = method.getDeclaringClass();
		String pack = _clazz.getPackage().getName();
		String className = _clazz.getSimpleName();
		className = className.substring(0, 1).toLowerCase() + className.substring(1);
		return pack + "." + className;
	}

	@Override
	protected void checkClass() throws IllegalClassException, IgnoredClassException {
	}

	@Override
	protected boolean isInterface() {
		return false;
	}

	@Override
	protected String getASClassName() {
		return method.getName()+"CacheService";
	}

	@Override
	protected String getASClassComment() throws NoCommentClassException {
		throw new NoCommentClassException();
	}

	@Override
	protected String getASSuperClassName() throws NoSuperClassException {
		return "AbstractMethodClass";
	}

	@Override
	protected Collection<String> getASInterfacesName() {
		return null;
	}

	@Override
	protected Set<String> getASImports() {
		Set<String> imports = getASDefaultImports();
		getASImportsFromMethod(method, imports);
		return imports;
	}

	@Override
	protected Collection<String> getASClassAnnotations() throws NoAnnotationClassException{
		Collection<String> annos = new ArrayList<String>();
		annos.add("[Entity]");
		annos.add("[ExcludeClass]");
		annos.add("[Table(name=\""+method.getDeclaringClass().getSimpleName()+"_"+method.getName()+"CacheService"+"\")]");
		return annos;
	}

	/**
	 * Retourne une liste d'imports par defaut.
	 * @return
	 */
	private Set<String> getASDefaultImports() {
		Set<String> imports = new HashSet<String>();
		imports.add("flash.utils.ByteArray");
		imports.add("hhf.services.methods.AbstractMethodClass");
		imports.add("mx.collections.ArrayCollection");
		imports.add("flash.errors.IllegalOperationError");
		imports.add("flash.utils.getQualifiedClassName");
		imports.add("mx.rpc.events.FaultEvent");
		return imports;
	}

	@Override
	protected Map<String, String> getASEvents() {
		Class<?>[] exceptions = method.getExceptionTypes();
		Map<String, String> map = new HashMap<String, String>();
		for (Class<?> ex : exceptions) {
			map.put("fault"+ex.getSimpleName(), "mx.rpc.events.FaultEvent");
		}
		return map;
	}

	@Override
	protected Set<String> getASNamespaces() {
		return null;
	}

	@Override
	protected void writeASBodyConstructor(OutputStreamWriter out) throws IOException {
	}

	@Override
	protected void writeASFieldsAndMethods(OutputStreamWriter out) throws IOException {
		if(!"void".equals(returnASType)) {
			Collection<String> annos = new ArrayList<String>();
			if(collectionOf!=null) {
				annos.add("[ArrayElementType(\""+collectionOf+"\")]");
				annos.add("[ManyToMany(cascade=\"PERSIST,MERGE\")]");
			} else {
				if(temporal) annos.add("[Temporal(value=\"TIMESTAMP\")]");
				else if(basic) annos.add("[Basic]");
				else annos.add("[ManyToOne(cascade=\"PERSIST,MERGE\")]");
			}
			insertASField(out, "datas", returnASType, false, false, false, annos);
		}
	}

	@Override
	protected void createSeeAlsoASClass() {
	}
}
